package com.lmy.springboot.project.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lmy.springboot.project.bean.Furn;
import com.lmy.springboot.project.service.FurnService;
import com.lmy.springboot.project.util.Result;
import com.lmy.springboot.project.util.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 因为当前项目是前后端分离项目，在默认情况下，前端发出请求，后端返回json数据
 * 为了方便，标识@RestController
 */
@RestController
@Slf4j
public class FurnController {

    @Resource
    private FurnService furnService;

    /**新增家居
     * 当前，前端是以json格式来发送添加的信息，所以需要添加@RequestBody来接收json数据并封装到Furn对象中
     * 加入@Validated来对请求的json对象属性进行指定的校验，校验通过才会将属性封装到javabean中。
     * 如果校验失败，就会将错误信息封装到Errors对象中
     * @param furn
     * @return
     */
    @PostMapping(value = "/saveFurn")
    public Result saveFurn(@Validated @RequestBody Furn furn, Errors errors) {
        log.info("saveFurn()接收到客户端/浏览器发送的json数据={}", furn);

        //定义一个map，如果有错误信息，就不提交，把errors中的校验错误放入到map中，返回给客户端
        Map<String, Object> hashMap = new HashMap<>();
        //获取错误信息
        List<FieldError> fieldErrors = errors.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            hashMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        if(hashMap.isEmpty()){  //说明没有校验错误
            furnService.save(furn);
            return Result.success();
        } else {    //有校验错误，就将错误信息返回给客户端
            return Result.info(ResultEnum.ValidError, hashMap);
        }

    }

    /**
     * 返回所有家居信息
     * @return
     */
    @GetMapping(value = "/listFurn")
    public Result listFurn() {
        List<Furn> list = furnService.list();
        return Result.success(list);
    }

    /**
     * 修改家居信息
     * @param furn
     * @return
     */
    @PutMapping(value = "/updateFurn")
    public Result updateFurn(@RequestBody Furn furn) {
        furnService.updateById(furn);
        return Result.success();
    }

    /**
     * 删除家居信息
     * @param id
     * @return
     */
    @DeleteMapping(value = "/deleteFurn")
    public Result deleteFurn(@RequestParam Integer id) {
        furnService.removeById(id);
        return Result.success();
    }

    /**
     * 分页查询
     * @param pageNum   显示第几页
     * @param pageSize  每页显示几条记录
     * @return
     */
    @GetMapping(value = "/listFurnByPage")
    public Result listFurnByPage(@RequestParam(defaultValue = "1") Integer pageNum,
                                 @RequestParam(defaultValue = "5") Integer pageSize) {
        //创建一个Page对象，根据pageNum和pageSize
        Page<Furn> pageObj = new Page<>(pageNum, pageSize);
        //调用分页查询方法，传入Page对象。返回一个Page对象，封装了分页数据
        Page<Furn> page = furnService.page(pageObj);
        return Result.success(page);
    }

    /**
     *  按条件分页查询数据
     * @param pageNum 页数
     * @param pageSize 每页数据条数
     * @param name 按条件查询
     * @return
     */
    @GetMapping(value = "/listFurnByConditionPage")
    public Result listFurnByConditionPage(@RequestParam(defaultValue = "1") Integer pageNum,
                                          @RequestParam(defaultValue = "5") Integer pageSize,
                                          @RequestParam(value = "name", defaultValue = "") String name) {
        //创建一个Page对象，根据pageNum和pageSize
        Page<Furn> pageObj = new Page<>(pageNum, pageSize);
        //创建一个QueryWrapper，可以将检索条件封装到QueryWrapper中
        QueryWrapper<Furn> query = Wrappers.query();
        if (StringUtils.hasText(name)) {
            query.like("name", name);
        }
        Page<Furn> page = furnService.page(pageObj, query);
        return Result.success(page);
    }


    /**
     *  使用lambdaQueryWrapper封装查询条件，完成检索
     * @param pageNum 页数
     * @param pageSize 每页数据条数
     * @param name 按条件查询
     * @return
     */
    @GetMapping(value = "/listFurnByLambda")
    public Result listFurnByLambda(@RequestParam(defaultValue = "1") Integer pageNum,
                                          @RequestParam(defaultValue = "5") Integer pageSize,
                                          @RequestParam(value = "name", defaultValue = "") String name) {
        //关于lambda表达式，这里使用的是 类名::实例方法
        //是lambda方法引用中一个不太容易理解的知识点
        /*
            1.Furn::getName 通过lambda表达式引用实例方法 getName
            2.这里就是把 Furn::getName 赋给 SFunction<T,R> 函数式接口
            3.看看SFunction<T,R>源码
                @FunctionalInterface
                public interface SFunction<T, R> extends Function<T, R>, Serializable {
                }
              它的父接口Function<T,R>
                @FunctionalInterface
                public interface Function<T, R> {
                    R apply(T t);   //抽象方法；表示根据类型T的参数，获取类型R的结果

                    //后面还有默认实现的方法 default标识
                }
            4.传入Furn::getName后，就相当于实现了SFunction<T, R>的apply()方法
            5.底层就会根据传入的方法Furn::getName 去得到该方法对应的属性映射的表的字段
            6.mybatis在xx.xml中，ResultMap用来自定义javabean和数据库表字段的映射关系
         */

        //创建一个Page对象，根据pageNum和pageSize
        Page<Furn> pageObj = new Page<>(pageNum, pageSize);
        //创建一个LambdaQueryWrapper，封装查询条件
        LambdaQueryWrapper<Furn> lambdaQueryWrapper = Wrappers.lambdaQuery();
        if (StringUtils.hasText(name)) {
            lambdaQueryWrapper.like(Furn::getName, name);
            //可以换一个写法
//            SFunction<Furn, Object> sf = Furn::getName;
//            sf.apply(new Furn());
//            lambdaQueryWrapper.like(sf, name);
        }
        Page<Furn> page = furnService.page(pageObj, lambdaQueryWrapper);
        log.info("page={}", page.getRecords());
        return Result.success(page);
    }
}
